package app;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;

import log.Log;
import log.LogToGuiObserver;
import config.Config;
import serverClient.StateController;
import serverClient.GuiChangeObserver;
import serverClient.ConfigChangeObserver;

public class App implements AppInterface {

	private final boolean DEBUG = false;

	private String version;
	private Config config;
	private Log log;
	private StateController st;

	public App(String version, String configFolder) {

		this.version = version;
		if(configFolder.equals("")) {
			config = new Config(); // This should normally be used
		}
		else {
			config = new Config(configFolder); // Is used for developing
		}
		log = new Log(config.getConfigDir(), config.getSaveLog());

		// Initiates the stateController
		st = new StateController(this.version, config.getConfigDir());
		st.setDir(config.getDirectory());
		st.setDir2(config.getSecondDir());
		st.setIP(config.getIPAddress());
		st.setListenPort(config.getListenPort());
		st.setStartListen(config.getStartListen());
		st.setStartListen(config.getStartListen());
		st.setLocalSync(config.getLocalSync());
		st.setSyncMode(config.getSyncMode());
		st.setAllowDelete(config.getAllowDelete());
		st.setDeleteWarning(config.getDeleteWarning());
		st.setIncludeHidden(config.getIncludeHidden());
		st.setUseExactTime(config.getUseExactTime());
	}

	public void addGuiChangeObserver(GuiChangeObserver gco) {
		st.addGuiChangeObserver(gco);
	}

	public void addConfigChangeObserver(ConfigChangeObserver cco) {
		st.addConfigChangeObserver(cco);
	}

	public void addLogToGuiObserver(LogToGuiObserver ltgo) {
		log.addLogToGuiObserver(ltgo);
	}

	public void initObservers() {
		st.addLogObserver(log);
		st.addConfigChangeObserver(config);
	}


	public String getSkinType() {
		return config.getSkinType();
	}

	public void setSkinType(String skinType) {
		config.setSkinType(skinType);
	}

	public String getGuiType() {
		return config.getGuiType();
	}

	public void setGuiType(String guiType) {
		config.setGuiType(guiType);
	}

	public boolean getVisibleGui() {
		return config.getVisibleGui();
	}

	public void setVisibleGui(boolean visibleGui) {
		config.setVisibleGui(visibleGui);
	}

	public String getLocalIp() {
		try {
			InetAddress addr = InetAddress.getLocalHost();

			// Get IP Address
			String hostAddr = addr.getHostAddress();
			return hostAddr;

		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return "error";
	}

	public String getNextLocalIP(String previousIP) {
		try {
			InetAddress addr = InetAddress.getLocalHost();

			// Get host name
			String hostname = addr.getHostName();

			InetAddress[] interAddr = InetAddress.getAllByName(hostname);

			// Get IP Address
			int temp = 0; //TODO ta bort
			if(DEBUG) System.out.println( "interAddr.length=" + interAddr.length + 
					"\nisAnyLocalAddress()=" + interAddr[temp].isAnyLocalAddress() + 
					"\nisLinkLocalAddress()=" + interAddr[temp].isLinkLocalAddress() +
					"\nisLoopbackAddress()=" + interAddr[temp].isLoopbackAddress() +
					"\nisMCGlobal()=" + interAddr[temp].isMCGlobal() +
					"\nisMCLinkLocal()=" + interAddr[temp].isMCLinkLocal() + 
					"\nisMCNodeLocal()=" + interAddr[temp].isMCNodeLocal() + 
					"\nisMCOrgLocal()=" + interAddr[temp].isMCOrgLocal() + 
					"\nisMCSiteLocal()=" + interAddr[temp].isMCSiteLocal() + 
					"\nisMulticastAddress()=" + interAddr[temp].isMulticastAddress() +
					"\nisSiteLocalAddress()=" + interAddr[temp].isSiteLocalAddress() +
					"\ntoString()=" + interAddr[temp].toString() );

			String hostAddr = interAddr[0].getHostAddress();
			for(int i=0; i<interAddr.length-1; i++) {
				if(interAddr[i].getHostAddress().equals(previousIP)) {
					hostAddr = interAddr[i+1].getHostAddress();
					break;
				}
			}
			return hostAddr;

		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return "error";
	}

	public String getLastConectionIP() {
		return config.getLastConectionIP();
	}

	public void setLastConectionIP(String lastConectionIP) {
		config.setLastConectionIP(lastConectionIP);
	}

	public String getLastSyncDoneMsg() {
		return config.getLastSyncDoneMsg();
	}

	public void setLastSyncDoneMsg(String lastSyncDoneMsg) {
		config.setLastSyncDoneMsg(lastSyncDoneMsg);
	}

	public String getIPAddress() {
		return config.getIPAddress();
	}

	public void setIPAddress(String ipadd) {
		config.setIPAddress(ipadd);
		st.setIP(config.getIPAddress());
	}

	public File getDirectory() {
		return new File( config.getDirectory() );
	}

	public void setDirectory(File directory) {

		if( !directory.getAbsolutePath().equals( config.getDirectory() ) ) {
			config.setDirectory( directory.getAbsolutePath() );
			st.setDir(config.getDirectory());
		}
	}

	public File getSecondDir() {
		return new File( config.getSecondDir() );
	}

	public void setSecondDir(File secondDir) {

		if( !secondDir.getAbsolutePath().equals( config.getSecondDir() ) ) {
			config.setSecondDir( secondDir.getAbsolutePath() );
			st.setDir2(config.getSecondDir());
		}
	}

	public boolean getLocalSync() {
		return config.getLocalSync();
	}

	public void setLocalSync(boolean localSync) {

		config.setLocalSync(localSync);

		st.setLocalSync(config.getLocalSync());
	}

	public boolean getStartListen() {
		return config.getStartListen();
	}

	// We start listening only after we initialized app and GUI
	// if we call StateController in any code before this the 
	// program will crash, so we have to catch any of those calls.
	public void setStartListen(boolean startListen) {
		config.setStartListen(startListen);

		st.setStartListen(config.getStartListen());

		if(startListen) {
			st.startStateController();
		}
		else {
			st.exit();
		}
	}

	public void startSync() {
		if(DEBUG) System.out.println("Starting sync...");

		st.startClientSync(config.getIPAddress(), config.getSendPort(), config.getSecondDir(), config.getLocalSync());
	}

	public void cancel() {
		st.resetThread();
	}

	public String getSyncMode() {
		return config.getSyncMode();
	}

	public void setSyncMode(String syncMode) {
		config.setSyncMode(syncMode);
		st.setSyncMode(syncMode);
	}

	public int getSendPort() {
		return config.getSendPort();
	}

	public void setSendPort(int sendPort) {
		config.setSendPort(sendPort);
		st.setSendPort(sendPort);
	}

	public int getListenPort() {
		return config.getListenPort();
	}

	public void setListenPort(int listenPort) {
		config.setListenPort(listenPort);
		st.setListenPort(listenPort);
	}

	public boolean getAutoSync() {
		return config.getAutoSync();
	}

	public void setAutoSync(boolean autoSync) {
		config.setAutoSync(autoSync);
	}

	public int getAutoSyncDelay() {
		return config.getAutoSyncDelay();
	}

	public void setAutoSyncDelay(int delayInMillisec) {
		config.setAutoSyncDelay(delayInMillisec);
	}

	public boolean getAllowDelete() {
		return config.getAllowDelete();
	}

	public void setAllowDelete(boolean allowDelete) {
		config.setAllowDelete(allowDelete);
		st.setAllowDelete(allowDelete);
	}

	public boolean getDeleteWarning() {
		return config.getDeleteWarning();
	}

	public void setDeleteWarning(boolean deleteWarning) {
		config.setDeleteWarning(deleteWarning);
		st.setDeleteWarning(deleteWarning);
	}

	public boolean getIncludeHidden() {
		return config.getIncludeHidden();
	}

	public void setIncludeHidden(boolean includeHidden) {
		config.setIncludeHidden(includeHidden);
		st.setIncludeHidden(includeHidden);
	}

	public boolean getUseExactTime() {
		return config.getUseExactTime();
	}

	public void setUseExactTime(boolean useExactTime) {
		config.setUseExactTime(useExactTime);
		st.setUseExactTime(useExactTime);
	}

	public boolean getSaveLog() {
		return config.getSaveLog();
	}

	public void setSaveLog(boolean saveLog) {
		config.setSaveLog(saveLog);
		log.setSaveLog(saveLog);
	}

	public void saveConfig() {
		config.saveConfig();
	}



	// Gives true if it is the first time that you start the Sync IT program
	public boolean getFirstStart() {
		return config.getNewConfigFileCreated();
	}



	public void openLogFileForReading() {
		log.openFileForReading();
	}

	public void closeLogFileReadingPart() {
		log.closeReadingPart();
	}

	public String getLogLine() {
		return log.getLogLine();
	}

	public void clearLog() {
		log.clearLogFile();
		if(DEBUG) System.out.println("Cleared Log");
	}



	public void removeOldRemoteFileLists() {
		File fileToDelete = new File(config.getConfigDir() + File.separator + "oldRemoteFileList.filel");
		if (fileToDelete.exists()) {
			if (fileToDelete.delete()) {
				if(DEBUG) System.out.println("oldRemoteFileList.filel successfully removed!");
			}
		}

		fileToDelete = new File(config.getConfigDir() + File.separator + "oldRemoteFileList2.filel");
		if (fileToDelete.exists()) {
			if (fileToDelete.delete()) {
				if(DEBUG) System.out.println("oldRemoteFileList2.filel successfully removed!");
			}
		}
	}

	public boolean doesOldRemoteFileListsExist() {
		File fileToDelete = new File(config.getConfigDir() + File.separator + "oldRemoteFileList.filel");
		if (fileToDelete.exists()) {
			return true;
		}

		fileToDelete = new File(config.getConfigDir() + File.separator + "oldRemoteFileList2.filel");
		if (fileToDelete.exists()) {
			return true;
		}
		return false;
	}

}
